package com.itzh.proxy.custom;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLDecoder;

public class GPProxy {


    public static final String ln = "\r\n";

    public static Object newProxyInstance(GPClassLoader classLoader,Class<?> [] interfaces,GPInvocationHandler handler) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        //动态生成源代码.java文件
        String src = generateSrc(interfaces);

        //把.java文件输出磁盘
        String filePath = GPProxy.class.getResource("").getPath();
        filePath = URLDecoder.decode(filePath,"utf-8");
        System.out.println(filePath);
        File file = new File(filePath+"$Proxy0.java");
        FileWriter fw = new FileWriter(file);
        fw.write(src);
        fw.flush();
        fw.close();
        //把生成的.java文件编译成class文件
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager manage = compiler.getStandardFileManager(null, null, null);
        Iterable<? extends JavaFileObject> iterable = manage.getJavaFileObjects(file);
        JavaCompiler.CompilationTask task = compiler.getTask(null, manage, null, null, null, iterable);
        task.call();
        manage.close();
        //编译生成的class文件，加载到JVM中来
        Class<?> proxyClass = classLoader.findClass("$Proxy0");
        Constructor<?> constructor = proxyClass.getConstructor(GPInvocationHandler.class);
        file.delete();
        //返回字节码重组后的新代理对象
        return constructor.newInstance(handler);
    }

    private static String generateSrc(Class<?> [] interfaces) {
        StringBuffer sb = new StringBuffer();

        sb.append("package com.itzh.proxy.custom;"+ln);
        sb.append("import com.itzh.proxy.state.Person;"+ln);
        sb.append("import java.lang.reflect.Method;"+ln);
        sb.append("public class $Proxy0 implements "+interfaces[0].getName()+"{"+ln);
            sb.append("GPInvocationHandler h;"+ln);
            sb.append("public $Proxy0(GPInvocationHandler h){"+ln);
            sb.append("this.h = h;");
        sb.append("}"+ln);
        for(Method m:interfaces[0].getMethods()){
            sb.append("public "+m.getReturnType().getName()+" "+m.getName()+"(){"+ln);
            sb.append("try{"+ln);
                sb.append("Method m = "+interfaces[0].getName()+".class.getMethod(\""+m.getName()+"\",new Class[]{});"+ln);
                sb.append("this.h.invoke(this,m,null);"+ln);
            sb.append("}catch(Throwable r){"+ln);
                sb.append("r.printStackTrace();");
            sb.append("}"+ln);
         sb.append("}"+ln);
        }
        sb.append("}"+ln);


        return sb.toString();
    }
}
